from flask import Flask, render_template, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import linear_kernel
import numpy as np
import random
import os
# 数据库配置 - 使用绝对路径
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'ecommerce2.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)


# 模型定义
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)


class Product(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(200), nullable=False)
    description = db.Column(db.Text)
    price = db.Column(db.Float, nullable=False)
    category = db.Column(db.String(100))
    brand = db.Column(db.String(100))
    image_url = db.Column(db.String(200))
    rating = db.Column(db.Float)
    reviews_count = db.Column(db.Integer)

    def to_dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'price': self.price,
            'image_url': self.image_url,
            'category': self.category,
            'brand': self.brand
        }


class UserBehavior(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    product_id = db.Column(db.Integer, db.ForeignKey('product.id'), nullable=False)
    action = db.Column(db.String(20), nullable=False)  # 'view', 'search', 'buy', 'add_to_cart'
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)


class MySearchHistory(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    query_text = db.Column(db.String(200), nullable=False)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)


# 搜索建议API - 基于协同过滤
@app.route('/api/suggestions', methods=['GET'])
def get_suggestions():
    query = request.args.get('query', '').strip().lower()
    user_id = request.args.get('user_id', 1, type=int)  # 实际项目中应从会话获取

    if len(query) < 2:
        return jsonify([])

    # 1. 基于内容的搜索建议
    content_based_suggestions = get_content_based_suggestions(query)

    # 2. 基于协同过滤的搜索建议
    collaborative_suggestions = get_collaborative_filtering_suggestions(user_id, query)

    # 3. 基于用户历史的搜索建议
    history_suggestions = get_history_based_suggestions(user_id, query)

    # 合并结果并去重
    suggestions = []
    suggestion_set = set()

    # 添加内容建议
    for suggestion in content_based_suggestions:
        if suggestion['value'].lower() not in suggestion_set:
            suggestion_set.add(suggestion['value'].lower())
            suggestions.append(suggestion)

    # 添加协同过滤
    for suggestion in collaborative_suggestions:
        if suggestion['value'].lower() not in suggestion_set:
            suggestion_set.add(suggestion['value'].lower())
            suggestions.append(suggestion)



    # 添加历史建议
    for suggestion in history_suggestions:
        print(suggestion)
        if suggestion['value'].lower() not in suggestion_set:
            suggestion_set.add(suggestion['value'].lower())
            suggestions.append(suggestion)

    return jsonify(suggestions[:10])


# 基于内容的搜索建议
def get_content_based_suggestions(query):
    products = Product.query.filter(
        (Product.name.ilike(f'%{query}%')) |
        (Product.description.ilike(f'%{query}%'))
    ).limit(5).all()


    return [
        {
            'type': 'product',
            'value': product.name,
            'data': product.to_dict()
        }
        for product in products
    ]


# 基于协同过滤的搜索建议
def get_collaborative_filtering_suggestions(user_id, query):
    # 获取用户最近的行为
    recent_behaviors = UserBehavior.query.filter(
        UserBehavior.user_id == user_id
    ).order_by(UserBehavior.timestamp.desc()).limit(10).all()
    if not recent_behaviors:
        return []

    # 获取相似用户喜欢的商品
    similar_user_products = get_similar_users_products(user_id)
    # 从相似用户喜欢的商品中筛选与查询相关的
    # relevant_products = []
    # for product in similar_user_products:
    #     if query.lower() in product.name.lower() or query.lower() in (product.description or '').lower():
    #         relevant_products.append(product)

    return [
        {
            'type': 'collaborative',
            'value': product.name,
            'data': product.to_dict()
        }
        for product in similar_user_products[:3]
    ]


# 获取相似用户喜欢的商品
def get_similar_users_products(user_id):
    # 这里实现协同过滤算法

    # 获取所有用户行为数据
    behaviors = UserBehavior.query.all()

    # 构建用户-商品交互矩阵
    user_item_matrix = {}
    for behavior in behaviors:
        if behavior.user_id not in user_item_matrix:
            user_item_matrix[behavior.user_id] = {}
        # 不同行为赋予不同权重
        if behavior.action == 'buy':
            weight = 3
        elif behavior.action == 'add_to_cart':
            weight = 2
        elif behavior.action == 'view':
            weight = 1
        else:  # search
            weight = 1.5

        user_item_matrix[behavior.user_id][behavior.product_id] = weight

    # 如果没有足够的数据，返回热门商品
    if len(user_item_matrix) < 2 or user_id not in user_item_matrix:
        return Product.query.order_by(Product.reviews_count.desc()).limit(5).all()

    # 计算当前用户与其他用户的相似度
    target_user = user_item_matrix[user_id]
    similarities = []

    for other_user_id, items in user_item_matrix.items():
        if other_user_id == user_id:
            continue

        # 计算余弦相似度
        dot_product = 0
        target_norm = 0
        other_norm = 0

        for item_id, weight in items.items():
            if item_id in target_user:
                dot_product += target_user[item_id] * weight
            other_norm += weight ** 2

        for item_id, weight in target_user.items():
            target_norm += weight ** 2

        if target_norm == 0 or other_norm == 0:
            similarity = 0
        else:
            similarity = dot_product / (np.sqrt(target_norm) * np.sqrt(other_norm))

        similarities.append((other_user_id, similarity))

    # 按相似度排序
    similarities.sort(key=lambda x: x[1], reverse=True)

    # 获取最相似的前3个用户
    top_similar_users = similarities[:3]
    # 从相似用户喜欢的商品中推荐
    recommended_products = set()
    for similar_user_id, _ in top_similar_users:
        for product_id in user_item_matrix[similar_user_id]:
            if product_id not in target_user:
                product = Product.query.get(product_id)
                if product:
                    recommended_products.add(product)

    return list(recommended_products)


# 基于用户历史的搜索建议
def get_history_based_suggestions(user_id, query):

    history_suggestions = MySearchHistory.query.filter(
        MySearchHistory.user_id == user_id,
        MySearchHistory.query_text.ilike(f"%{query}%")  # 假设字段名为query_text
    ).order_by(MySearchHistory.timestamp.desc()).limit(5).all()

    return [
        {
            'type': 'history',
            'value': history.query_text,
            'data': {'query': history.query_text}
        }
        for history in history_suggestions
    ]


# 搜索功能
@app.route('/search', methods=['GET'])
def search():
    query = request.args.get('query', '')
    category = request.args.get('category')
    brand = request.args.get('brand')
    min_price = request.args.get('min_price', type=float)
    max_price = request.args.get('max_price', type=float)

    # 记录搜索历史
    user_id = 1  # 假设已登录用户
    if query:
        search_history = MySearchHistory(user_id=user_id, query_text=query)
        db.session.add(search_history)

        # 记录用户搜索行为
        products = Product.query.filter(
            (Product.name.ilike(f'%{query}%')) |
            (Product.description.ilike(f'%{query}%'))
        ).limit(3).all()

        # 保存用户行为数据
        for product in products:
            behavior = UserBehavior(
                user_id=user_id,
                product_id=product.id,
                action='search'
            )
            db.session.add(behavior)
        #
        db.session.commit()

    # 执行搜索
    products = search_products(query, category, brand, min_price, max_price)

    return render_template('search_results.html', products=products, query=query)


# 搜索商品的辅助函数
def search_products(query, category=None, brand=None, min_price=None, max_price=None):
    query = query.strip()
    base_query = Product.query

    if query:
        base_query = base_query.filter(
            (Product.name.ilike(f'%{query}%')) |
            (Product.description.ilike(f'%{query}%'))
        )

    if category:
        base_query = base_query.filter(Product.category == category)

    if brand:
        base_query = base_query.filter(Product.brand == brand)

    if min_price is not None:
        base_query = base_query.filter(Product.price >= min_price)

    if max_price is not None:
        base_query = base_query.filter(Product.price <= max_price)

    # 按相关性和销量排序
    return base_query.order_by(Product.reviews_count.desc()).all()


# 首页
@app.route('/')
def index():
    # 获取热门商品
    trending_products = Product.query.order_by(Product.reviews_count.desc()).limit(8).all()

    # 获取推荐商品
    user_id = 1  # 假设已登录用户
    user_recs = get_user_recommendations(user_id)

    return render_template('base.html', trending=trending_products, user_recs=user_recs)


# 获取用户推荐
def get_user_recommendations(user_id):
    # 使用协同过滤获取推荐商品
    recommended_products = get_similar_users_products(user_id)

    # 如果推荐不足，补充热门商品
    if len(recommended_products) < 4:
        hot_products = Product.query.order_by(Product.reviews_count.desc()).all()
        for product in hot_products:
            if product not in recommended_products:
                recommended_products.append(product)
            if len(recommended_products) >= 4:
                break

    return recommended_products[:4]


# 初始化示例数据
def init_sample_data():
    if Product.query.count() == 0:
        # 添加示例产品
        sample_products = [
            {
                'id': 1,
                'name': '苹果 iPhone 14 Pro 256GB',
                'description': '6.1英寸超视网膜XDR显示屏，A16仿生芯片，4800万像素主摄',
                'price': 7999.0,
                'category': '手机',
                'brand': '苹果',
                'image_url': 'https://picsum.photos/seed/iphone14/400/400',
                'rating': 4.8,
                'reviews_count': 1204
            },
            {
                'id': 2,
                'name': '华为 Mate 50 Pro 256GB',
                'description': '6.74英寸OLED屏幕，骁龙8+ 4G芯片，超光变摄像头苹果',
                'price': 6799.0,
                'category': '手机',
                'brand': '华为',
                'image_url': 'https://picsum.photos/seed/mate50/400/400',
                'rating': 4.7,
                'reviews_count': 987
            },
            {
                'id': 3,
                'name': '小米 13 Pro 256GB',
                'description': '6.73英寸2K屏幕，骁龙8 Gen2芯片，徕卡三摄',
                'price': 5999.0,
                'category': '手机',
                'brand': '小米',
                'image_url': 'https://picsum.photos/seed/xiaomi13/400/400',
                'rating': 4.6,
                'reviews_count': 856
            },
            {
                'id': 4,
                'name': '三星 Galaxy S23 Ultra 256GB',
                'description': '6.8英寸2K AMOLED屏幕，骁龙8 Gen2芯片，2亿像素主摄',
                'price': 8999.0,
                'category': '手机',
                'brand': '三星',
                'image_url': 'https://picsum.photos/seed/s23ultra/400/400',
                'rating': 4.7,
                'reviews_count': 732
            },
            {
                'id': 5,
                'name': 'Apple Watch Series 8',
                'description': '45毫米铝金属表壳，全天候视网膜显示屏，血氧检测',
                'price': 3199.0,
                'category': '智能手表',
                'brand': '苹果',
                'image_url': 'https://picsum.photos/seed/aw8/400/400',
                'rating': 4.6,
                'reviews_count': 1120
            },
            {
                'id': 6,
                'name': '华为 Watch GT 3 Pro',
                'description': '46毫米钛金属表壳，圆形屏幕，精准心率监测',
                'price': 2499.0,
                'category': '智能手表',
                'brand': '华为',
                'image_url': 'https://picsum.photos/seed/gt3pro/400/400',
                'rating': 4.5,
                'reviews_count': 980
            },
            {
                'id': 7,
                'name': '小米 Watch S1 Pro',
                'description': '1.43英寸AMOLED屏幕，117种运动模式，50米防水',
                'price': 1299.0,
                'category': '智能手表',
                'brand': '小米',
                'image_url': 'https://picsum.photos/seed/miw1/400/400',
                'rating': 4.4,
                'reviews_count': 760
            },
            {
                'id': 8,
                'name': 'AirPods Pro 2',
                'description': '主动降噪，通透模式，自适应均衡，IP54防水防尘',
                'price': 1899.0,
                'category': '耳机',
                'brand': '苹果',
                'image_url': 'https://picsum.photos/seed/airpods2/400/400',
                'rating': 4.7,
                'reviews_count': 1540
            },
            {
                'id': 9,
                'name': '华为 FreeBuds Pro 2',
                'description': '主动降噪，高解析度音频，双单元设计',
                'price': 1199.0,
                'category': '耳机',
                'brand': '华为',
                'image_url': 'https://picsum.photos/seed/hwbuds2/400/400',
                'rating': 4.6,
                'reviews_count': 1230
            },
            {
                'id': 10,
                'name': '小米 Buds 4 Pro',
                'description': '主动降噪，HiFi音质，通透模式，无线充电',
                'price': 799.0,
                'category': '耳机',
                'brand': '小米',
                'image_url': 'https://picsum.photos/seed/xmbuds4/400/400',
                'rating': 4.5,
                'reviews_count': 980
            },
            {
                'id': 11,
                'name': '苹果耳机Pro',
                'description': '主动降噪，HiFi音质，通透模式，无线充电',
                'price': 799.0,
                'category': '耳机',
                'brand': '苹果',
                'image_url': 'https://picsum.photos/seed/xmbuds4/400/400',
                'rating': 4.5,
                'reviews_count': 980
            }
        ]

        for product_data in sample_products:
            product = Product(**product_data)
            db.session.add(product)

        db.session.commit()

        # 添加示例用户
        user = User(username='test_user', email='test@example.com')
        db.session.add(user)
        db.session.commit()

        # 添加示例用户行为
        user_id = user.id
        product_ids = [p.id for p in Product.query.all()]

        # 用户1的行为
        for i, product_id in enumerate(product_ids[:5]):
            actions = ['view', 'search', 'add_to_cart', 'buy', 'view']
            for action in actions:
                behavior = UserBehavior(
                    user_id=user_id,
                    product_id=product_id,
                    action=action
                )
                db.session.add(behavior)

        # 添加一些其他用户的行为，用于协同过滤
        for other_user_id in range(2, 6):
            other_user = User(username=f'user{other_user_id}', email=f'user{other_user_id}@example.com')
            db.session.add(other_user)
            db.session.commit()

            # 每个用户随机喜欢一些商品
            liked_products = random.sample(product_ids, random.randint(3, 6))
            for product_id in liked_products:
                action = random.choice(['view', 'add_to_cart', 'buy'])
                behavior = UserBehavior(
                    user_id=other_user_id,
                    product_id=product_id,
                    action=action
                )
                db.session.add(behavior)

        db.session.commit()


if __name__ == '__main__':
    with app.app_context():
        db.create_all()
        # 初始化一些示例数据
        init_sample_data()

        # for i in range(5):
        #     behavior = UserBehavior(
        #         user_id=1,
        #         product_id=i + 1,
        #         action='search'
        #     )
        #     db.session.add(behavior)
        # for i in range(6, 10):
        #     behavior = UserBehavior(
        #         user_id= 2,
        #         product_id=i ,
        #         action='search'
        #     )
        #     db.session.add(behavior)
        # db.session.commit()
    app.run(debug=True)
